package com.hspedu.qqclient.service;

import com.hspedu.qqcommon.Message;
import com.hspedu.qqcommon.MessageType;
import com.hspedu.qqcommon.User;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @author 谷其昊
 * @version 1.0
 * @date 2022/3/17
 * @time 19:11
 * 该类完成用户注册和用户登录等功能
 */
public class UserClientService {

    /**
     * 需要在这里调用构造器，指向堆中的具体对象
     * 如果我们只是声明
     * 在每个方法中根据声明重新 new 对象
     * 会改变这个 user 的指向
     * 对于一个客户端进程，我们只需要一个user对象
     * 我们的目的只是修改对象的属性即可
     */
    User user = new User();

    /**
     * 到服务器验证用户是否合法
     *
     * @param userId   用户名
     * @param password 用户密码
     * @return 是否存在该用户
     */
    public boolean checkUser(String userId, String password) {
        user.setUserId(userId);
        user.setPassword(password);
        Socket socket = null;
        //将User发送给服务器做验证
        try {
            socket = new Socket(InetAddress.getByName("127.0.0.1"), 9999);
            OutputStream outputStream = socket.getOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
            objectOutputStream.writeObject(user);
            //下面这句话会导致EOFException
//            socket.shutdownOutput();
        } catch (IOException e) {
            e.printStackTrace();
        }

        //从服务器读取返回值
        //我们自己写，返回一个 Message 对象
        Message message = null;
        try {
            InputStream inputStream = socket.getInputStream();
            ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
            message = (Message) objectInputStream.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //根据message的类型判断
        if (message.getMessageType().equals(MessageType.MESSAGE_LOGIN_SUCCESS)) {
            //登录成功之后，还需要为当前socket开启一个线程
            ClientConnectServerThread clientConnectServerThread = new ClientConnectServerThread(socket);
            clientConnectServerThread.start();
            ManageClientConnectServerThread.addClientConnectServerThread(userId, clientConnectServerThread);
            return true;
        } else {
            //登陆失败，但是socket是已经建立的
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }

        return false;

    }

    /**
     * 向服务器请求在线用户列表
     */
    public void getOnlineFriendList() {
        Message message = new Message();
        message.setMessageType(MessageType.MESSAGE_GET_ONLINE_FRIEND);
        message.setSender(user.getUserId());
        ClientConnectServerThread thread = ManageClientConnectServerThread.getClientConnectServerThread(user.getUserId());
        Socket socket = thread.getSocket();
        try {
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(message);
            objectOutputStream.flush();
//            这里不能使用线程插队，我的想法是输出语句是在子线程
//              让子线程输出完之后流程再转到主线程
//            但是子线程是个无限循环，第一次正常卡在主线程之前输出，但是子线程无限循环并且阻塞
//                    子线程如果插队，main线程无法正常执行
//            ClientConnectServerThread thread1 = ManageClientConnectServerThread.getClientConnectServerThread(user.getUserId());
//            thread1.join();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 客户端向服务端请求退出
     */
    public void clientRequestExit() {
        Message message = new Message();
        message.setMessageType(MessageType.MESSAGE_CLIENT_EXIT);
        message.setSender(user.getUserId());
        ClientConnectServerThread thread =
                ManageClientConnectServerThread.getClientConnectServerThread(user.getUserId());
        try {
            ObjectOutputStream oos = new ObjectOutputStream(thread.getSocket().getOutputStream());
            oos.writeObject(message);
            oos.flush();
            System.out.println("退出系统");
            System.exit(0);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 客户端请求私聊
     *
     * @param targetUserName 私聊的对象的用户名
     * @param content        私聊的内容
     */
    public void privateChat(String targetUserName, String content) {
        Message message = new Message();
        message.setMessageType(MessageType.MESSAGE_COMM_MES);
        message.setSender(user.getUserId());
        message.setGetter(targetUserName);
        message.setContent(content);
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分ss秒");
        String sendTime = dtf.format(now);
        message.setSendTime(sendTime);
        ObjectOutputStream objectOutputStream = null;
        ClientConnectServerThread thread =
                ManageClientConnectServerThread.getClientConnectServerThread(user.getUserId());
        Socket socket = thread.getSocket();
        try {
            objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
            objectOutputStream.writeObject(message);
            objectOutputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void groupChat(String content) {
        Message message = new Message();
        LocalDateTime now = LocalDateTime.now();
        String pattern = "yyyy年MM月dd日 HH时mm分ss秒";
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        String sendTime = dateTimeFormatter.format(now);
        message.setSendTime(sendTime);
        message.setSender(user.getUserId());
        message.setMessageType(MessageType.MESSAGE_TO_ALL);
        message.setContent(content);

        ClientConnectServerThread thread =
                ManageClientConnectServerThread.getClientConnectServerThread(user.getUserId());
        Socket socket = thread.getSocket();
        try {
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeObject(message);
            oos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 为消息设置发送时间
     * @param message
     */
    public void setMessageSendTime(Message message){
        LocalDateTime now = LocalDateTime.now();
        String pattern = "yyyy年MM月dd日 HH时mm分ss秒";
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        String sendTime = dateTimeFormatter.format(now);
        message.setSendTime(sendTime);
    }

    /**
     * 客户端向指定用户发送文件
     *
     * @param srcFilePath  源文件地址
     * @param destFilePath 目标文件地址
     */
    public void transferBinaryFile(String targetUser, String srcFilePath, String destFilePath) {
        File srcFile = null;
        try {
            //检测输入的地址是否为空
            srcFile = new File(srcFilePath);
        } catch (Exception e) {
            System.out.println("输入的地址不能为空");
            return;
        }
        FileInputStream fileInputStream = null;
        try {

            fileInputStream = new FileInputStream(srcFile);
            byte[] buf = new byte[(int) srcFile.length()];
            fileInputStream.read(buf);
            Message message = new Message();
            message.setBinaryContent(buf);
            message.setDestFilePath(destFilePath);
            message.setMessageType(MessageType.MESSAGE_BINARY_DATA);
            message.setGetter(targetUser);
            message.setSender(user.getUserId());
            setMessageSendTime(message);

            ClientConnectServerThread thread =
                    ManageClientConnectServerThread.getClientConnectServerThread(user.getUserId());
            Socket socket = thread.getSocket();
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeObject(message);
            oos.flush();

        } catch (FileNotFoundException e) {
            System.out.println("文件不存在，请重新选择并输入");
            return;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}
